#[derive(Debug, Clone, PartialEq)]
pub enum TokenKind {
    Integer,
    Float,
    LParen,
    RParen,
    Plus,
    Minus,
    Star,
    Slash,
    Mod,

    Eq,
    EqEq,
    Gt,
    GtEq,
    Lt,
    LtEq,

    String,
    Identifier,

    Let,
    If,
    Else,
    True,
    False,
    Print,

    Whitespace,
    Comment,
    Newline,
    Bad,
}

impl std::fmt::Display for TokenKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Integer => write!(f, "Integer"),
            Self::Float => write!(f, "Float"),
            Self::LParen => write!(f, "("),
            Self::RParen => write!(f, ")"),
            Self::Plus => write!(f, "+"),
            Self::Minus => write!(f, "-"),
            Self::Star => write!(f, "*"),
            Self::Slash => write!(f, "/"),
            Self::Mod => write!(f, "%"),

            Self::Gt => write!(f, ">"),
            Self::GtEq => write!(f, ">="),
            Self::Lt => write!(f, "<"),
            Self::LtEq => write!(f, "<="),

            Self::String => write!(f, "String"),

            Self::Identifier => write!(f, "Identifier"),

            Self::Let => write!(f, "Let"),
            Self::If => write!(f, "If"),
            Self::Else => write!(f, "else"),
            Self::True => write!(f, "True"),
            Self::False => write!(f, "False"),

            Self::Print => write!(f, "Print"),

            Self::Whitespace => write!(f, "WhiteSpace"),
            Self::Comment => write!(f, "Comment"),

            Self::Eq => write!(f, "="),
            Self::EqEq => write!(f, "=="),

            Self::Newline => write!(f, "Newline"),
            Self::Bad => write!(f, "Bad"),
        }
    }
}

#[derive(Debug, Clone)]
pub struct Token {
    pub kind: TokenKind,
    pub lexeme: String,
    pub line: usize,
}

impl Token {
    pub fn new(kind: TokenKind, lexeme: String, line: usize) -> Self {
        Self { kind, lexeme, line }
    }
}
